package com.zhugy.comparecode;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class BatchFileFetcher {

	static String file_name = "d:\\tmp\\2.txt";

	static ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(8);

	private static final BufferedWriter errorLogBW;
	
	private static final AtomicInteger appendCount = new AtomicInteger(0);
	private static final AtomicInteger completeCount = new AtomicInteger(0);
	static {
		try {
			errorLogBW = new BufferedWriter(new FileWriter("D:\\err.log"));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file_name)));
		String line;
		while ((line = br.readLine()) != null) {
			final String lineInner = line;
			if (lineInner == null || lineInner.length() == 0) {
				continue;
			}
			appendCount.incrementAndGet();
			pool.submit(() -> {
				String[] lineSp = lineInner.split(" ");
				String url = "https://h5.msyidai.com/file/open?fileId=" + lineSp[2];
				String fileName = lineSp[0] + "-" + lineSp[1] +".pdf";
				String fullFileName = "D:\\tmp\\contract20211105\\" + fileName;
				downLoadFromUrlHttps(url, fullFileName, lineInner);
				completeCount.incrementAndGet();
			});
		}
		while (appendCount.get() != completeCount.get()) {
			Thread.sleep(500);
		}
		pool.shutdown();
		errorLogBW.close();
		br.close();
	}

	public static void downLoadFromUrlHttps(String urlStr, String fullFileName, String line) {
		try {
			// 创建SSLContext
			SSLContext sslContext = SSLContext.getInstance("SSL");
			TrustManager[] tm = { new X509TrustManager() {

				@Override
				public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

				}

				@Override
				public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

				}

				@Override
				public X509Certificate[] getAcceptedIssuers() {
					return null;
				}
			} };
			// 初始化
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 获取SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();
			// url对象
			URL url = new URL(urlStr);
			// 打开连接
			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			/**
			 * 这一步的原因: 当访问HTTPS的网址。您可能已经安装了服务器证书到您的JRE的keystore
			 * 但是服务器的名称与证书实际域名不相等。这通常发生在你使用的是非标准网上签发的证书。
			 * 
			 * 解决方法：让JRE相信所有的证书和对系统的域名和证书域名。
			 * 
			 * 如果少了这一步会报错:java.io.IOException: HTTPS hostname wrong: should be <localhost>
			 */
			conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
			// 设置一些参数
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			// 设置当前实例使用的SSLSoctetFactory
			conn.setSSLSocketFactory(ssf);
			conn.connect();

			// 输出流
			File file = new File(fullFileName);
			FileOutputStream fos = new FileOutputStream(file);
			// 得到输入流
			InputStream inputStream = conn.getInputStream();
			copyInputStream(inputStream, fos);
			if (fos != null) {
				fos.close();
			}
			if (inputStream != null) {
				inputStream.close();
			}
		} catch (Exception e) {
			try {
				errorLogBW.write(line);
				errorLogBW.newLine();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
	}

	public static void copyInputStream(InputStream inputStream, FileOutputStream fos) throws IOException {
		byte[] b = new byte[1024];
		int len = 0;
		while ((len = inputStream.read(b)) != -1) {
			fos.write(b, 0, len);
		}
	}

	public static class TrustAnyHostnameVerifier implements HostnameVerifier {
		public boolean verify(String hostname, SSLSession session) {
			// 直接返回true:默认所有https请求都是安全的
			return true;
		}
	}

}
